/*
 * =====================================================================================
 *       Filename:  http.c
 * =====================================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <netdb.h>
#include <stdarg.h>
#include "../zipmap.h"
#include "../dict.h"
#include "../config.h"
#include "../factory.h"
#include "http.h"

#define HTTP_BUFFER_SIZE QUEUE_CACHE_LENGTH
static char _buf[HTTP_BUFFER_SIZE], _headers[HTTP_BUFFER_SIZE];
static char _method[16], _queue_name[128], _key[128], _value[256];
static int _lwritten = 1;

static void parseMQ(const char* line, char* method, int method_size, char* queue_name, int queue_name_size)
{
    int i, j;
    int size = method_size - 1;
    j = 0;
    for (i = 0; line[i] != ' ' && j < size; i++, j++) {
        method[j] = line[i];
    }
    method[j] = '\0';

    while (line[i] == ' ') i++;
    if (line[i] == '/') i++;

    size = queue_name_size - 1;
    j = 0;
    for ( ; ; i++, j++) {
        if (j >= size) break;
        if (line[i] == ' ' || line[i] == '\n' || line[i] == '\0')
            break;
        if (line[i] == '/')
            queue_name[j] = '-';
        else
            queue_name[j] = line[i];
    }
    queue_name[j] = '\0';

    if (strlen(queue_name) == 0) {
        strncpy(queue_name, "default", 8);
    }
}

static void parseKV(const char* line, char* key, int key_size, char* value, int value_size)
{
    const char* p = line;
    int i = 0;
    while (1) {
        key[i] = *p;
        if (*p == ':') {
            key[i] = '\0';
            break;
        }
        if ((*p == '\n') || (*p == '\0') || (i >= key_size - 1)) {
            key[0] = '\0';
            value[0] = '\0';
            return;
        }
        p++;
        i++;
    }
    
    while((*p == ':') || (*p == ' '))
        p++;

    i = 0;
    while(1) {
        value[i] = *p;
        if ((*p == '\n') || (*p == '\0') || (i >= value_size - 1)) {
            value[i] = '\0';
            break;
        }
        p++;
        i++;
    }
}

static int getLine(int fd)
{
    int i = 0;
    char c = '\0';

    int n, size = sizeof(_buf);
    while ((i < size - 1) && (c != '\n'))
    {
        n = recv(fd, &c, 1, 0);
        if (-1 == n && errno == EAGAIN){
            /* NOTE:
             * 如果客户端的数据分多批进入，并且不断开连接（比如手工telnet，或者恶意请求),
             * 如果简单的continue，会导致cpu极高的占用，并且堵塞于此，无法处理其他请求。
             * 应设定一个时限，或者采取其他限制策略。此处直接退出循环，忽略后面的数据。*/
            /* continue; */
            c = '\n';
        }
        else if (n > 0)
        {
            if (c == '\r')
            {
                n = recv(fd, &c, 1, MSG_PEEK);
                if ((n > 0) && (c == '\n'))
                    recv(fd, &c, 1, 0);
                else
                    c = '\n';
            }
            _buf[i] = c;
            i++;
        }
        else
            c = '\n';
    }
    _buf[i] = '\0';

    return i;
}

static void discardLeft(int fd)
{
    int n = 1;
    while (n > 0) {
        n = read(fd, _buf, HTTP_BUFFER_SIZE);
    }
}

static void httpEcho(int fd, const char* buf)
{
    if (_lwritten > 0) {
        _lwritten = write(fd, buf, strlen(buf));
    }
}

static void httpReply(int fd, int status, const char *queue_name, int count, const char *data)
{
    httpEcho(fd, "HTTP/1.1 200 OK\r\n");
    httpEcho(fd, "Content-Type: text/plain\r\n");
    sprintf(_buf, "Status: %d\r\n", status);
    httpEcho(fd, _buf);
    sprintf(_buf, "Queue: %s\r\n", queue_name);
    httpEcho(fd, _buf);
    sprintf(_buf, "Count: %d\r\n", count);
    httpEcho(fd, _buf);
    httpEcho(fd, "Powered-By: simq\r\n\r\n");

    if (data != NULL) {
        httpEcho(fd, data);
    }
}

#include "verbs.c"
#include "handle.c"

void cmdInit()
{
    int num = sizeof(_httpCommandTable) / sizeof(httpCommand);
    int i;
    _commands = dictCreate(&dictTypeStringKey);
    for (i = 0; i < num; i++) {
        dictSet(_commands, _httpCommandTable[i].name, _httpCommandTable + i);
    }
}

void cmdFree()
{
    dictFree(_commands);
}

